package niu.fencer.tool.qrcode.util;

import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.provider.MediaStore;
import android.widget.Toast;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLConnection;

/** android 10 存储权限
 * https://juejin.cn/post/6844903946000187406
 * https://zhuanlan.zhihu.com/p/128558892
 */
public class FileUtil {
    public static boolean SavePictureFile(Context context, File file) {
        if (file == null) {
            return false;
        }
        Uri uri = insertFileIntoMediaStore(context, file, true);
        return SaveFile(context, file, uri);
    }

    public static boolean SaveVideoFile(Context context, File file) {
        if (file == null) {
            return false;
        }
        Uri uri = insertFileIntoMediaStore(context, file, false);
        return SaveFile(context, file, uri);
    }

    public static void saveFile(byte[][] data, File file) {
        // 创建String对象保存文件名路径
        try {
            // 创建指定路径的文件
            // 如果文件不存在
            if (file.exists()) {
                // 创建新的空文件
                file.delete();
            }
            file.createNewFile();
            // 获取文件的输出流对象
            FileOutputStream outStream = new FileOutputStream(file);
            // 获取字符串对象的byte数组并写入文件流
            for (int i = 0; i < data.length; i++) {
                outStream.write(data[i]);
            }
            outStream.flush();
            outStream.close();
            // 最后关闭文件输出流
            outStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    private static boolean SaveFile(Context context, File file, Uri uri) {
        if (uri == null) {
            LogUtil.e("url is null");
            return false;
        }
        LogUtil.i("SaveFile: " + file.getName());
        ContentResolver contentResolver = context.getContentResolver();

        ParcelFileDescriptor parcelFileDescriptor = null;
        try {
            parcelFileDescriptor = contentResolver.openFileDescriptor(uri, "w");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        if (parcelFileDescriptor == null) {
            LogUtil.e("parcelFileDescriptor is null");
            return false;
        }

        FileOutputStream outputStream = new FileOutputStream(parcelFileDescriptor.getFileDescriptor());
        FileInputStream inputStream;
        try {
            inputStream = new FileInputStream(file);
        } catch (FileNotFoundException e) {
            LogUtil.e(e.toString());
            try {
                outputStream.close();
            } catch (IOException ex) {
                LogUtil.e(ex.toString());
            }
            return false;
        }

        try {
            copy(inputStream, outputStream);
        } catch (IOException e) {
            LogUtil.e(e.toString());
            return false;
        } finally {
            try {
                outputStream.close();
            } catch (IOException e) {
                LogUtil.e(e.toString());
            }
            try {
                inputStream.close();
            } catch (IOException e) {
                LogUtil.e(e.toString());
            }
        }

        return true;
    }

    //注意当文件比较大时该方法耗时会比较大
    private static void copy(InputStream ist, OutputStream ost) throws IOException {
        byte[] buffer = new byte[4096];
        int byteCount;
        while ((byteCount = ist.read(buffer)) != -1) {
            ost.write(buffer, 0, byteCount);
        }
        ost.flush();
    }

    //创建视频或图片的URI
    private static Uri insertFileIntoMediaStore(Context context, File file, boolean isPicture) {
        ContentValues contentValues = new ContentValues();
        contentValues.put(MediaStore.Video.Media.DISPLAY_NAME, file.getName());
        contentValues.put(MediaStore.Video.Media.MIME_TYPE, isPicture ? "image/jpeg" : "video/mp4");
        if (Build.VERSION.SDK_INT >= 29) {
            contentValues.put(MediaStore.Video.Media.DATE_TAKEN, file.lastModified());
        }

        Uri uri = null;
        try {
            uri = context.getContentResolver().insert(
                    (isPicture ? MediaStore.Images.Media.EXTERNAL_CONTENT_URI : MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
                    , contentValues
            );
        } catch (Exception e) {
            e.printStackTrace();
        }
        return uri;
    }

    /**
     * 创建图片地址uri,用于保存拍照后的照片 Android 10以后使用这种方法
     */
    private Uri  createImageUri(Context context) {
        String status = Environment.getExternalStorageState();
        // 判断是否有SD卡,优先使用SD卡存储,当没有SD卡时使用手机存储
        if (status.equals(Environment.MEDIA_MOUNTED)) {
            return context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new ContentValues());
        } else {
            return context.getContentResolver().insert(MediaStore.Images.Media.INTERNAL_CONTENT_URI, new ContentValues());
        }
    }

    public static String getMimeType(File file) {
        String guess = null;
        if (file != null && file.exists() && file.isFile()) {
            InputStream is = null;
            try {
                is = new BufferedInputStream(new FileInputStream(file));
                guess = URLConnection.guessContentTypeFromStream(is);
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                if (is != null) {
                    try {
                        is.close();
                    } catch (IOException ignored) {
                    }
                }
            }

            if (guess == null || guess.isEmpty()) {
                guess = "*/*";
                String filename = file.getName().replace(".jenc", "");
                int dot = filename.lastIndexOf(".") + 1;
                if (dot > 0 && dot < filename.length()) {
                    switch (filename.substring(dot)) {
                        case "md":
                        case "markdown":
                        case "mkd":
                        case "mdown":
                        case "mkdn":
                        case "mdwn":
                        case "rmd":
                            guess = "text/markdown";
                            break;
                        case "txt":
                            guess = "text/plain";
                            break;
                    }
                }
            }
        }
        return guess;
    }

    public static boolean isTextFile(File file) {
        String mime = getMimeType(file);
        return mime != null && mime.startsWith("text/");
    }

    public static boolean writeFile(final File file, byte[] data) {
        try {
            OutputStream output = null;
            try {
                output = new BufferedOutputStream(new FileOutputStream(file));
                output.write(data);
                output.flush();
                return true;
            } catch (Exception ex) {
                LogUtil.e("writeFile:"+file.getAbsolutePath(),ex);
                return false;
            } finally{
                if (output != null) {
                    output.close();
                }
            }
        } catch (Exception ex) {
            return false;
        }

    }

    public static byte[] readFileFast(final File file) {
        try {
            return readCloseStreamWithSize(new FileInputStream(file), (int) file.length());
        } catch (FileNotFoundException e) {

            System.err.println("readTextFileFast: File " + file + " not found.");
            e.printStackTrace();
        }
        return null;
    }

    public static byte[] readCloseStreamWithSize(final InputStream stream, int size) {
        byte[] data = new byte[size];
        try (DataInputStream dis = new DataInputStream(stream)) {
            dis.readFully(data);
        } catch (IOException ignored) {
        }
        return data;
    }
    public static String getFileSize(File file) {
        String modifiedFileSize = null;
        double fileSize = 0.0;
        if (file.isFile()) {
            fileSize = (double) file.length();//in Bytes

            if (fileSize < 1024) {
                modifiedFileSize = String.valueOf(file.length()).concat("B");
            } else if (fileSize > 1024 && fileSize < (1024 * 1024)) {
                modifiedFileSize = String.valueOf(Math.round((fileSize / 1024 * 100.0)) / 100.0).concat("KB");
            } else {
                modifiedFileSize = String.valueOf(Math.round((fileSize / (1024 * 1204) * 100.0)) / 100.0).concat("MB");
            }
        } else {
            modifiedFileSize = "";
        }

        return modifiedFileSize;
    }

    public static  void savePackageFile(Context context,String filename,String text,int mode) {
        FileOutputStream outputStream;

        try {
            outputStream = context.openFileOutput(filename, mode);
            outputStream.write(text.getBytes());
            outputStream.flush();
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static  void savePackageFile(Context context,String filename,byte[][] data,int mode) {
        FileOutputStream outputStream;

        try {
            outputStream = context.openFileOutput(filename, mode);
            for (int i = 0; i < data.length; i++) {
                outputStream.write(data[i]);
            }
            outputStream.flush();
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static  void savePackageFile(Context context,String filename,byte[] data,int mode) {
        FileOutputStream outputStream;

        try {
            outputStream = context.openFileOutput(filename, mode);
            outputStream.write(data);
            outputStream.flush();
            outputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static  String readPackageFile(Context context, String filename) {
        FileInputStream inputStream;
        StringBuilder sb = new StringBuilder("");
        try {
            inputStream = context.openFileInput(filename);

            byte temp[] = new byte[1024];

            int len = 0;
            while ((len = inputStream.read(temp)) > 0){
                sb.append(new String(temp, 0, len));
            }
            inputStream.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
        return sb.toString();
    }

    //往SD卡写入文件的方法
    public void savaFileToSD(Context context,String filename, String filecontent) throws Exception {
        //如果手机已插入sd卡,且app具有读写sd卡的权限
        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            filename = Environment.getExternalStorageDirectory().getCanonicalPath() + "/" + filename;

            //这里就不要用openFileOutput了,那个是往手机内存中写数据的
            FileOutputStream output = new FileOutputStream(filename);
            output.write(filecontent.getBytes());
            //将String字符串以字节流的形式写入到输出流中
            output.close();
            //关闭输出流
        } else Toast.makeText(context, "SD卡不存在或者不可读写", Toast.LENGTH_SHORT).show();
    }

    //读取SD卡中文件的方法
//定义读取文件的方法:
    public String readFromSD(String filename) throws IOException {
        StringBuilder sb = new StringBuilder("");
        if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            filename = Environment.getExternalStorageDirectory().getCanonicalPath() + "/" + filename;
            //打开文件输入流
            FileInputStream input = new FileInputStream(filename);
            byte[] temp = new byte[1024];

            int len = 0;
            //读取文件内容:
            while ((len = input.read(temp)) > 0) {
                sb.append(new String(temp, 0, len));
            }
            //关闭输入流
            input.close();
        }
        return sb.toString();
    }

}
